package com.ddwl.shop.service;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ddwl.common.constant.BaseEnum;
import com.ddwl.common.constant.GateEnum;
import com.ddwl.common.constant.RedisKey;
import com.ddwl.common.constant.ShopEnum;
import com.ddwl.common.exception.CommonException;
import com.ddwl.common.exception.ExceptionCode;
import com.ddwl.common.exception.ParamException;
import com.ddwl.common.feign.api.*;
import com.ddwl.common.service.RedisService;
import com.ddwl.common.util.*;
import com.ddwl.schema.bo.base.PageBo;
import com.ddwl.schema.bo.goods.ShopItemDefaultCategoryBo;
import com.ddwl.schema.bo.shop.*;
import com.ddwl.schema.bo.user.FenxiaoRegisterBo;
import com.ddwl.schema.bo.user.RegBo;
import com.ddwl.schema.bo.user.UserBo;
import com.ddwl.schema.model.Location;
import com.ddwl.schema.util.DateUtil;
import com.ddwl.schema.vo.base.PageVo;
import com.ddwl.schema.vo.base.RestVo;
import com.ddwl.schema.vo.gate.RegionVo;
import com.ddwl.schema.vo.order.ShopOrderDataVo;
import com.ddwl.schema.vo.shop.*;
import com.ddwl.schema.vo.user.IdentityCardVo;
import com.ddwl.schema.vo.user.ShareCodeInfoVo;
import com.ddwl.shop.dao.ShopDao;
import com.ddwl.shop.dao.ShopMemberDao;
import com.ddwl.shop.dao.ShopStaffDao;
import com.ddwl.shop.dao.ShopUserRecordDao;
import com.ddwl.shop.dao.model.*;
import com.ddwl.shop.repository.ShopLocRepository;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.util.StringUtil;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Fu Zhaohui
 * @version 1.0.0.RELEASE
 * @date 2020/3/5 11:00 上午
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ShopService {

    private final ShopDao shopDao;
    private final ShopCategoryService shopCategoryService;
    private final ShopUserRecordService shopUserRecordService;
    private final UserApi userApi;
    private final WalletApi walletApi;
    private final GoodsApi goodsApi;
    private final RedisService redisService;
    private final OrderApi orderApi;
    private final ShopUserRecordDao shopUserRecordDao;
    private final GateApi gateApi;
    private final ShopStaffDao shopStaffDao;
    private final ShopMemberDao shopMemberDao;
    private final ShopDistributionService shopDistributionService;
    private final ShopLocRepository shopLocRepository;

    @Transactional(rollbackFor = Throwable.class)
    public void createShop(ShopBo bo, String userId) {
        ParamException.isNotNull(bo.getId(), "id不为空");
        Shop shop = BeanConverUtils.convertBean(bo, Shop.class);
        shop.setStatus(0);
        shop.setType(0);
        shop.setLogisticsTag(0);
        shop.setLocalDeliveryTag(0);
        shop.setCreatedUserId(userId);
        shop.setModifiedUserId(null);
        shop.setGmtModified(null);
        shop.setDefaultTag(0);
        shop.setSystemStop(0);
        shop.setReserved(0);
        shop.setSelfMentionTag(1);
        shop.setBusBegin("0:00");
        shop.setBusEnd("24:00");
        shop.setBeforeUsedName("");
        shop.setNotice("欢迎来到" + shop.getName());
        shop.setLastUpdateTime(DateUtil.getTimesMorning(Instant.now(), -30));
        shop.setConsumerServiceTel(bo.getUserTel());

        Integer hasIdCard = 1;
        FenxiaoRegisterBo fenxiaoRegisterBo = new FenxiaoRegisterBo();

        IdentityCardVo identityCardVo = userApi.getIdCardByUserId(userId).getResult();
        ParamException.isTrue(identityCardVo != null && !identityCardVo.getIdCard().equals(bo.getUserIdCard()), "当前用户已绑定其他身份证号,请联系管理员解绑");
        IdentityCardVo identityCardVo2 = userApi.getIdCardByTel(bo.getUserTel()).getResult();
        ParamException.isTrue(identityCardVo2 != null && !identityCardVo2.getIdCard().equals(bo.getUserIdCard()), "当前手机号已绑定其他身份证号,请联系管理员解绑");
//        shop.setFenxiaoId(vo.getId());
        //查询当前用户与身份证号信息
        List<IdentityCardVo> cardVos = userApi.getIdCardByCode(bo.getUserIdCard()).getResult();
        ParamException.isTrue(cardVos != null && cardVos.size() > 1, "当前身份证信息验证有误,请联系管理员");
        if (!CollectionUtils.isEmpty(cardVos)) {
            ParamException.isFalse(cardVos.get(0).getUserId().equals(userId), "当前身份证已绑定其他手机号,请联系管理员解绑");
        } else {
            hasIdCard = 0;
        }

        String salt = RandomGenerateUtil.getRandomS(0, 6);
        shop.setSalt(salt);
        if (!CollectionUtils.isEmpty(bo.getShopCategoryVoList())) {
            StringBuffer cate = new StringBuffer();
            bo.getShopCategoryVoList().stream().forEach(o -> cate.append(o.getShopCategoryCode()).append(","));
            shop.setCategory(cate.toString().substring(0, cate.length() - 1));
        }
        shop.setPassword(EncryptUtil.encryptMD5(salt + EncryptUtil.encryptMD5(bo.getUserTel().substring(bo.getUserTel().length() - 6))));
        shopDao.insert(shop);
        if(!shop.getType().equals(ShopEnum.TypeEnum.DRIVER)) {
            ShopLoc shopLoc = BeanConverUtils.convertBean(shop, ShopLoc.class);
            shopLoc.setShopId(shop.getId());
            shopLoc.setLoc(new Location(shop.getLng(), shop.getLat()));
            shopLocRepository.save(shopLoc);
        }
        //生成分销员身份证信息
        if (hasIdCard == 0) {
            fenxiaoRegisterBo.setId(shop.getUserId());
            fenxiaoRegisterBo.setMobile(shop.getUserTel());
            fenxiaoRegisterBo.setRegionId(shop.getRegionId());
            fenxiaoRegisterBo.setAdder(shop.getAddress());
            fenxiaoRegisterBo.setIdName(shop.getUserName());
            fenxiaoRegisterBo.setIdCard(bo.getUserIdCard());
            fenxiaoRegisterBo.setIdCardBack(bo.getIdCardBack());
            fenxiaoRegisterBo.setIdCardFront(bo.getIdCardFront());
            userApi.createProfile(fenxiaoRegisterBo);
        }

 /*       //生成银行卡信息
        //查询用户银行卡信息
        WithdrawChannelVo withdrawChannelVo = walletApi.getUserBankCard(bo.getBankCardNumber()).getResult();
        if (withdrawChannelVo!=null){
            ParamException.isFalse(withdrawChannelVo.getUserId().equals(vo.getId()),"银行卡已经被绑定到其他用户,请联系管理员解绑");
        }else {
            WithdrawChannelAddBo withdrawChannelAddBo=new WithdrawChannelAddBo();
            withdrawChannelAddBo.setUserId(vo.getId());
            withdrawChannelAddBo.setRealName(bo.getAccountName());
            withdrawChannelAddBo.setIdcard(bo.getUserIdCard());
            withdrawChannelAddBo.setType(2);
            withdrawChannelAddBo.setShopId(insert.getId());
            withdrawChannelAddBo.setBankName(bo.getBankName());
            //withdrawChannelAddBo.setBankCode();
            withdrawChannelAddBo.setAccount(bo.getBankCardNumber());
            withdrawChannelAddBo.setBankAddress(bo.getBankAddress());
            withdrawChannelAddBo.setMobile(insert.getUserTel());
            walletApi.fenxiaoWithdrawChannel(withdrawChannelAddBo);
        }
*/
        setDefaultDistribution(shop);
        //生成默认分类
        ((ShopService) AopContext.currentProxy()).createDefaultCategory(shop.getId());
        //生成店铺二维码
        ((ShopService) AopContext.currentProxy()).createShopWxaCode(shop.getId(), shop.getUserId());
    }

    private void setDefaultDistribution(Shop shop) {
        shopDistributionService.setDefault(shop.getId(), shop.getLocalDeliveryTag(), shop.getLogisticsTag(), shop.getRegionId(), shop.getProvinceName(), shop.getCityName(), shop.getDistrictName(), shop.getAddress(), shop.getLng(), shop.getLat(), shop.getBusBegin(), shop.getBusEnd());
    }

    @Async
    public void createShopWxaCode(String shopId, String userId) {
        Shop shop = new Shop();
        shop.setId(shopId);
        String wxaCode = getWxaCodeOSSUrl(shopId);
        shop.setWxaCode(wxaCode);
        shopDao.updateByPrimaryKeySelective(shop);
        UserBo bo = new UserBo();
        bo.setId(userId);
        bo.setShopWxaCode(wxaCode);
        userApi.saveShopWxaCode(bo);
    }

    @Async
    public void createDefaultCategory(String shopId) {
        ShopItemDefaultCategoryBo goods = new ShopItemDefaultCategoryBo();
        goods.setShopId(shopId);
        goodsApi.addDefaultCategoryForApi(goods);
    }

    public String getWxaCodeOSSUrl(String shopId) {
        String imageName = shopId + "_" + RandomUtil.randomNumbers(4);
        saveShareCodeInfoToRedis(shopId);
        RestVo<String> stringRestVo = gateApi.wxaCodeUnlimit(shopId, BaseEnum.WxAppId.WBM.getCode(), String.format(GateEnum.WxaPath.SHOP_WXA_CODE.getPath(), imageName), null);
        if (StrUtil.isEmpty(stringRestVo.getResult())) {
            return null;
        }
        return stringRestVo.getResult();
    }

    private void saveShareCodeInfoToRedis(String shopId) {
        ShareCodeInfoVo sciVo = new ShareCodeInfoVo();
        sciVo.setShopId(shopId);
        redisService.getValueOps().set(RedisKey.SHARE_CODE_INFO.getKey(shopId), JSON.toJSONString(sciVo));
    }

    @GlobalTransactional(rollbackFor = Throwable.class)
    public void updateShop(ShopUpdateBo bo, String userId) {
        Shop entity = shopDao.selectByPrimaryKey(bo.getId());
        log.info("shop info:[{}]", JSON.toJSONString(entity));
        doUpdateShop(bo, userId);
        checkLogistic(bo.getId());
        updateShopWxacode(bo, entity);
    }

    @GlobalTransactional(rollbackFor = Throwable.class)
    public void updateShopName(ShopUpdateBo bo, String userId) {
        Shop entity = shopDao.selectByPrimaryKey(bo.getId());
        log.info("shop info:[{}]", JSON.toJSONString(entity));
        ParamException.isTrue(bo.getName().equals(entity.getName()), "新店铺名称与之前名称相同");
        ParamException.isTrue(ChronoUnit.DAYS.between(entity.getLastUpdateTime(), Instant.now()) < 30L, "30天以内只能更改一次名字");
        Shop shop = new Shop();
        shop.setId(entity.getId());
        shop.setName(bo.getName());
        shop.setModifiedUserId(userId);
        shop.setLastUpdateTime(Instant.now());
        shop.setBeforeUsedName(entity.getBeforeUsedName() + "," + entity.getName());
        shopDao.updateByPrimaryKeySelective(shop);
    }

    private String fillAddr(String province, String city, String district, String address) {
        StringBuilder sb = new StringBuilder();
        if (StrUtil.isNotEmpty(province)) {
            sb.append(province);
        }
        if (StrUtil.isNotEmpty(city)) {
            sb.append(city);
        }
        if (StrUtil.isNotEmpty(district)) {
            sb.append(district);
        }
        if (StrUtil.isNotEmpty(address)) {
            sb.append(address);
        }
        return sb.toString();
    }

    private void updateShopDistribution(String addr, String busBegin, String busEnd, Integer selfMentionTag, Integer localDeliveryTag, Integer logisticsTag, String shopId) {
        ShopDistribution sd = new ShopDistribution();
        if (StrUtil.isNotEmpty(addr)) {
            sd.setTakeAddr(addr);
        }
        if (StrUtil.isNotEmpty(busBegin)) {
            sd.setBusBegin(busBegin);
        }
        if (StrUtil.isNotEmpty(busEnd)) {
            sd.setBusEnd(busEnd);
        }
        sd.setSelfMentionTag(selfMentionTag);
        sd.setLocalDeliveryTag(localDeliveryTag);
        sd.setLogisticsTag(logisticsTag);
        shopDistributionService.updateShopDistributionByShopId(sd, shopId);
    }

    private void doUpdateShop(ShopUpdateBo bo, String userId) {
        ParamException.isBlank(bo.getId(), "shopId为空");
        Shop shop = BeanConverUtils.convertBean(bo, Shop.class);
        if (StringUtil.isNotEmpty(bo.getRegionId())) {
            RegionVo regionVo = gateApi.geoRegion(bo.getRegionId()).getResult();
            shop.setProvinceName(regionVo.getProvinceName());
            shop.setCityName(regionVo.getCityName());
            shop.setDistrictName(regionVo.getDistrictName());
        }
        shop.setName(null);
        shop.setDefaultTag(null);
        shop.setUserId(null);
        shop.setModifiedUserId(userId);
        shopDao.updateByPrimaryKeySelective(shop);
        ShopLoc shopLoc = shopLocRepository.findById(bo.getId()).orElse(null);
        if (shopLoc != null) {
            BeanUtils.copyProperties(bo, shopLoc, ObjectUtil.getNullFields(bo));
            shopLocRepository.save(shopLoc);
        }
        String addr = fillAddr(shop.getProvinceName(), shop.getCityName(), shop.getDistrictName(), shop.getAddress());
        updateShopDistribution(addr, bo.getBusBegin(), bo.getBusEnd(), bo.getSelfMentionTag(), bo.getLocalDeliveryTag(), bo.getLogisticsTag(), bo.getId());
    }

    public void updateShopWxacode(ShopUpdateBo bo, Shop entity) {
        if (StrUtil.isNotEmpty(bo.getLogo())) {
            if (!bo.getLogo().equals(entity.getLogo())) {
                String logoUrl = bo.getLogo();
                int index = logoUrl.lastIndexOf("/", logoUrl.lastIndexOf("/") - 1) + 1;
                if (index > 0) {
                    String logoStr = logoUrl.substring(index);
                    ((ShopService) AopContext.currentProxy()).customizeLogoWxaCode(bo.getId(), entity.getUserId(), logoStr);
                }
            }
        } else {
            ((ShopService) AopContext.currentProxy()).createShopWxaCode(bo.getId(), entity.getUserId());
        }
    }

    @Transactional(rollbackFor = Throwable.class)
    public void updateShopNotice(String notice, String shopId) {
        ParamException.isBlank(shopId, "shopId为空");
        Shop shop = new Shop();
        shop.setNotice(notice);
        shop.setId(shopId);
        shopDao.updateByPrimaryKeySelective(shop);
    }

    @Transactional(rollbackFor = Throwable.class)
    public void updateShopStatus(Integer status, String shopId) {
        ParamException.isBlank(shopId, "shopId为空");
        Shop shop = new Shop();
        shop.setStatus(status);
        shop.setId(shopId);
        shopDao.updateByPrimaryKeySelective(shop);
    }

    @Async
    public void customizeLogoWxaCode(String shopId, String userId, String logoStr) {
        String customizeWxaCode = customizeLogoWxaCodeUrl(shopId, logoStr);
        if (StrUtil.isNotEmpty(customizeWxaCode)) {
            Shop shop = new Shop();
            shop.setId(shopId);
            shop.setWxaCode(customizeWxaCode);
            shopDao.updateByPrimaryKeySelective(shop);
            UserBo bo = new UserBo();
            bo.setId(userId);
            bo.setShopWxaCode(customizeWxaCode);
            userApi.saveShopWxaCode(bo);
        }
    }

    public String customizeLogoWxaCodeUrl(String id, String logoStr) {
        String imageName = id + "_" + RandomUtil.randomNumbers(4);
        saveShareCodeInfoToRedis(id);
        RestVo<String> stringRestVo = gateApi.customizeLogoWxaCodeUrl(id, BaseEnum.WxAppId.WBM.getCode(), String.format(GateEnum.WxaPath.SHOP_WXA_CODE.getPath(), imageName), logoStr, null);
        if (StrUtil.isEmpty(stringRestVo.getResult())) {
            return null;
        }
        return stringRestVo.getResult();
    }


    @Transactional(rollbackFor = Throwable.class)
    public void update(ShopBo bo, String userId) {
        ParamException.isBlank(bo.getId(), "id为空");
        Shop shop1 = shopDao.selectByPrimaryKey(bo.getId());
        ParamException.isTrue(shop1.getDefaultTag() == 1 && ((bo.getStatus() != null && bo.getStatus() == 0) || (bo.getSystemStop() != null && bo.getSystemStop() == 1)), "官方店铺不能关闭");
        Shop shop = BeanConverUtils.convertBean(bo, Shop.class);
        if (!CollectionUtils.isEmpty(bo.getStoreImg1())) {
            shop.setStoreImg1(String.join(",", bo.getStoreImg1()));
        }
        if (!CollectionUtils.isEmpty(bo.getShopCategoryVoList())) {
            StringBuffer cate = new StringBuffer("");
            bo.getShopCategoryVoList().stream().forEach(o -> {
                cate.append(o.getShopCategoryCode()).append(",");
            });
            shop.setCategory(cate.toString().substring(0, cate.length() - 1));
        }
        if (StringUtil.isNotEmpty(bo.getRegionId())) {
            RegionVo regionVo = gateApi.geoRegion(bo.getRegionId()).getResult();
            ParamException.isNull(regionVo, "区域id为空");
            shop.setProvinceName(regionVo.getProvinceName());
            shop.setCityName(regionVo.getCityName());
            shop.setDistrictName(regionVo.getDistrictName());
            Object result = gateApi.geoLoc(regionVo.getCityName(),
                    regionVo.getProvinceName() + regionVo.getCityName() + regionVo.getDistrictName() + bo.getAddress()).getResult();
            if (result != null) {
                JSONObject job = ((JSONArray) result).getJSONObject(0);
                if (job.get("location") != null) {
                    String[] loc = job.get("location").toString().split(",");
                    shop.setLng(Double.valueOf(loc[0]));
                    shop.setLat(Double.valueOf(loc[1]));
                }
            }

        }
        shop.setModifiedUserId(userId);
        shop.setDefaultTag(null);
        shopDao.updateByPrimaryKeySelective(shop);
        String addr = fillAddr(shop.getProvinceName(), shop.getCityName(), shop.getDistrictName(), shop.getAddress());
        updateShopDistribution(addr, shop.getBusBegin(), shop.getBusEnd(), shop.getSelfMentionTag(), shop.getLocalDeliveryTag(), shop.getLogisticsTag(), shop.getId());
    }


    @Transactional(rollbackFor = Throwable.class)
    public void stopShop(String shopId, Integer systemStop, String userId) {
        ParamException.isBlank(shopId, "id为空");
        Shop shop1 = shopDao.selectByPrimaryKey(shopId);
        ParamException.isTrue(shop1.getDefaultTag() == 1 && (systemStop != null && systemStop == 1), "官方店铺不能关闭");
        Shop shop = new Shop();
        shop.setId(shopId);
        shop.setSystemStop(systemStop);
        shop.setModifiedUserId(userId);
        shopDao.updateByPrimaryKeySelective(shop);
    }

    @Transactional(rollbackFor = Throwable.class)
    public void deleteShop(String shopId, String userId) {
        ParamException.isBlank(shopId, "id为空");
        shopDao.deleteById(shopId, userId);
    }

    public ShopVo getByIdShopConsole(String id) {
        ParamException.isBlank(id, "id为空");
        Shop shop = shopDao.queryShop(id);
        ShopVo shopVo = BeanConverUtils.convertBean(shop, ShopVo.class);
        if (shopVo == null) {
            return null;
        }
        setShopStoreImg(shop.getStoreImg1(), shopVo);
        shopVo.setShopCategoryVoList(shopCategoryService.getShopCategory(shopVo.getCategory()));
        return shopVo;
    }

    public ShopVo getById(String id, String userId, String userName) {
        Shop shop = getProperShop(id, userId);
        ShopVo shopVo = BeanConverUtils.convertBean(shop, ShopVo.class);
        if (null != shopVo) {
            setShopStoreImg(shop.getStoreImg1(), shopVo);
            setShopCategoryName(shopVo);
            shopVo.setUserName(null);
            shopVo.setUserTel(null);
            ((ShopService) AopContext.currentProxy()).saveShopUserRecord(shopVo.getId(), userId, userName);
        }
        return shopVo;
    }

    public ShopVo getDefaultShop() {
        Shop shop = shopDao.queryShop(1);
        ShopVo shopVo = BeanConverUtils.convertBean(shop, ShopVo.class);
        if (null != shopVo) {
            setShopStoreImg(shop.getStoreImg1(), shopVo);
            setShopCategoryName(shopVo);
        }
        return shopVo;
    }

    private void setShopStoreImg(String storeImg, ShopVo shopVo) {
        if (StringUtil.isNotEmpty(storeImg)) {
            storeImg = storeImg.replaceAll("\\[", "").replaceAll("\\]", "");
            shopVo.setStoreImg1(Arrays.asList(storeImg.split(",")));
        }
    }

    private Shop getProperShop(String id, String userId) {
        Shop shop = null;
        if (StrUtil.isNotEmpty(id)) {
            shop = shopDao.selectByPrimaryKey(id);
        } else {
            if (StrUtil.isNotEmpty(userId)) {
                //如果登录人是店主,默认店主店铺
                shop = shopDao.getShopByUserId(userId);
                if (null == shop) {
                    String shopId = shopUserRecordService.queryRelateRecord(userId);
                    //邀请人店铺不存在,就显示上次登录门店
                    if (StrUtil.isNotEmpty(shopId)) {
                        shop = shopDao.selectByPrimaryKey(shopId);
                    }
                }
            }
            if (checkShopStatus(shop)) {
                shop = shopDao.queryShop(1);
            }
        }
        return shop;
    }

    private boolean checkShopStatus(Shop shop) {
        return shop == null || shop.getStatus() == 0 || shop.getSystemStop() == 1;
    }

    /**
     * 填充分类名称
     */
    private String fileCategoryName(List<ShopCategoryVo> shopCategory) {
        StringBuffer categoryName = new StringBuffer("");
        shopCategory.stream().forEach(o -> {
            categoryName.append(o.getShopCategoryName()).append(",");
        });
        if (!categoryName.equals("")) {
            return categoryName.substring(0, categoryName.length() - 1);
        }
        return null;
    }

    public ShopVo getShop(String id) {
        Shop shop = shopDao.selectByPrimaryKey(id);
        ShopVo shopVo = BeanConverUtils.convertBean(shopDao.selectByPrimaryKey(id), ShopVo.class);
        if (shopVo != null) {
            shopVo.setPasswordStatus(StrUtil.isNotEmpty(shop.getPassword()) ? 1 : 0);
        }
        return shopVo;
    }

    public ShopVo getShopForApi(String id) {
        ShopVo shopVo = BeanConverUtils.convertBean(shopDao.queryShop(id), ShopVo.class);
        if (shopVo == null) {
            return null;
        }
        setShopCategoryName(shopVo);
        return shopVo;
    }

    public ShopVo getShopByUserIdApi(String userId) {
        Shop shop = new Shop();
        shop.setUserId(userId);
        ShopVo shopVo = BeanConverUtils.convertBean(shopDao.selectOne(shop), ShopVo.class);
        if (shopVo == null) {
            return null;
        }
        if (shopVo.getNotice() == null) {
            shopVo.setNotice("");
        }
        if (shopVo.getLogo() == null) {
            shopVo.setLogo("");
        }
        setShopCategoryName(shopVo);
        return shopVo;
    }

    public ShopVo getShopByOpenId(String shopId) {
        ParamException.isBlank(shopId, "门店id为空");
        Shop shop = shopDao.selectByPrimaryKey(shopId);
        ShopVo shopVo = BeanConverUtils.convertBean(shop, ShopVo.class);
        if (shopVo == null) {
            return null;
        }
        if (shopVo.getNotice() == null) {
            shopVo.setNotice("");
        }
        if (shopVo.getLogo() == null) {
            shopVo.setLogo("");
        }
        setShopCategoryName(shopVo);
        if (shopVo.getLastUpdateTime() != null && ChronoUnit.DAYS.between(shop.getLastUpdateTime(), Instant.now()) < 30L) {
            shopVo.setIsUpdateName(0);
        } else {
            shopVo.setIsUpdateName(1);
        }
        return shopVo;
    }

    /**
     * 根据手机号查询门店账号信息
     *
     * @return
     */
    public ShopAccountVo getShopByMobile(String mobile) {
        Shop query = new Shop();
        query.setUserTel(mobile);
        Shop shop = shopDao.selectOne(query);
        if (shop == null) {
            return null;
        }
        ShopAccountVo shopAccountVo = new ShopAccountVo();
        shopAccountVo.setUserId(shop.getUserId());
        shopAccountVo.setShopId(shop.getId());
        shopAccountVo.setShopName(shop.getName());
        shopAccountVo.setUsername(shop.getUserTel());
        shopAccountVo.setNickname(shop.getUserName());
        shopAccountVo.setPassword(shop.getPassword());
        shopAccountVo.setSalt(shop.getSalt());
        shopAccountVo.setStatus(shop.getSystemStop());
        return shopAccountVo;
    }

    public ShopVo getShopByUserIdApi() {
        Shop shop = new Shop();
        shop.setDefaultTag(1);
        return BeanConverUtils.convertBean(shopDao.selectOne(shop), ShopVo.class);
    }

    public ShopVo getDetailConsole(QueryShopBo bo) {
        Shop shop = shopDao.queryShopDetailConsole(bo);
        ShopVo shopVo = BeanConverUtils.convertBean(shop, ShopVo.class);
        if (shopVo == null) {
            return null;
        }
        setShopStoreImg(shop.getStoreImg1(), shopVo);
        setShopCategoryName(shopVo);
        return shopVo;
    }

    public void setShopCategoryName(ShopVo shopVo) {
        List<ShopCategoryVo> shopCategory = shopCategoryService.getShopCategory(shopVo.getCategory());
        if (!CollectionUtils.isEmpty(shopCategory)) {
            shopVo.setShopCategoryName(fileCategoryName(shopCategory));
        }
        shopVo.setShopCategoryVoList(shopCategory);
    }

    public void setShopCategoryName(ShopMemberDto shopVo) {
        List<ShopCategoryVo> shopCategory = shopCategoryService.getShopCategory(shopVo.getCategory());
        if (!CollectionUtils.isEmpty(shopCategory)) {
            shopVo.setShopCategoryName(fileCategoryName(shopCategory));
        }
        shopVo.setShopCategoryVoList(shopCategory);
    }

    public PageVo<ShopVo> getShopList(PageBo<QueryShopBo> boPageBo) {
        PageHelper.startPage(boPageBo.getPage(), boPageBo.getPageSize(), MySqlUtil.orderBy(boPageBo.getSort(), boPageBo.isAsc()));
        PageInfo<ShopVo> info = new PageInfo(shopDao.queryShopList(boPageBo.getParam()));
        List<ShopVo> list = BeanConverUtils.convertBeanList(info.getList(), ShopVo.class);
        //填充门店金额
        List<ShopVo> shopVos = fileShopAmounts(list);
        return new PageVo<>(info.getTotal(), boPageBo.getPage(), boPageBo.getPageSize(), shopVos);
    }

    /**
     * 填充门店金额
     */
    private List<ShopVo> fileShopAmounts(List<ShopVo> list) {
        List<String> userIds = list.stream().filter(shopVo -> StrUtil.isNotEmpty(shopVo.getFenxiaoId())).map(ShopVo::getFenxiaoId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(userIds)) {
            Map<String, BigDecimal> result = walletApi.queryUserWalletList(userIds).getResult();
            list.stream().forEach(o -> {
                o.setShopAmount(result.get(o.getFenxiaoId()) == null ? BigDecimal.ZERO : result.get(o.getFenxiaoId()));
            });
        }
        return list;
    }

    public List<ShopVo> getShops(QueryShopBo boPageBo) {
        List<ShopVo> list = BeanConverUtils.convertBeanList(shopDao.queryShopList(boPageBo), ShopVo.class);
        return list;
    }

    @Transactional(rollbackFor = Throwable.class)
    public void changeShopPwd(String shopId, ShopRegBo bo) {
        Shop shop = shopDao.selectByPrimaryKey(shopId);
        ParamException.isNull(shop, "店铺数据存在问题");
        if (!StringUtil.isEmpty(shop.getPassword())) {
            if (StringUtil.isNotEmpty(bo.getOldPassword())) {
                String saltPassword = EncryptUtil.encryptMD5(shop.getSalt() + bo.getOldPassword());
                if (!saltPassword.equals(shop.getPassword())) {
                    throw new CommonException("旧密码错误");
                }
            } else {
                validMobileCode(shop.getUserTel(), bo.getCode());
            }
        }
        shop.setPassword(EncryptUtil.encryptMD5(shop.getSalt() + bo.getNewPassword()));
        shopDao.updateByPrimaryKeySelective(shop);
    }

    @Transactional(rollbackFor = Throwable.class)
    public void resetShopPwd(RegBo bo) {
        validMobileCode(bo.getMobile(), bo.getCode());
        Shop shop = new Shop();
        shop.setUserTel(bo.getMobile());
        Shop entity = shopDao.selectOne(shop);
        if (entity == null) {
            throw new CommonException(ExceptionCode.DATA_NOT_EXISTS);
        }
        entity.setPassword(EncryptUtil.encryptMD5(entity.getSalt() + bo.getPassword()));
        shopDao.updateByPrimaryKeySelective(entity);
        clearShopToken(entity.getUserId());
    }

    private void validMobileCode(String mobile, String code) {
        String authCode = redisService.getValueOps().get(RedisKey.MOBILE_REST_SMS_KEY.getKey(mobile));
        ParamException.isTrue(!code.equals(authCode), ExceptionCode.MOBILE_AUTH_FAILED.getMsg());
    }

    /**
     * 清除用户所有平台登录认证Token
     *
     * @param userId
     */
    public void clearShopToken(String userId) {
        HashOperations<String, String, String> ops = redisService.getHashOps();
        String tokenKey = RedisKey.TOKEN_KEY.getKey("*", userId);
        Set<String> keys = ops.keys(tokenKey);
        keys.forEach(key -> {
            String token = ops.get(key, "ak");
            String product = ops.get(key, "pk");
            String authKey = RedisKey.AUTH_KEY.getKey(product, token);
            ops.getOperations().delete(key);
            ops.getOperations().delete(authKey);
        });
    }

    public String getShopIdByUserId(String userId) {
        Shop shop = new Shop();
        shop.setUserId(userId);
        Shop one = shopDao.selectOne(shop);
        ParamException.isNull(one, "当前用户没有门店");
        return one.getId();

    }

    @Async
    public void saveShopUserRecord(String shopId, String userId, String userName) {
        ShopUserRecordBo bo = new ShopUserRecordBo();
        bo.setShopId(shopId);
        bo.setUserId(userId);
        bo.setLoginTime(Instant.now());
        bo.setUserName(userName);
        shopUserRecordService.saveShopUserRecord(bo);
    }

    @Transactional(rollbackFor = Throwable.class)
    public void changeShopLogistics(String shopId, Integer logisticsTag, String userId) {
        Shop entity = new Shop();
        entity.setId(shopId);
        entity.setLogisticsTag(logisticsTag);
//        entity.setLocalDeliveryTag(logisticsTag);
        entity.setGmtModified(Instant.now());
        entity.setModifiedUserId(userId);
        shopDao.updateByPrimaryKeySelective(entity);
        checkLogistic(shopId);
        ShopDistribution sd = new ShopDistribution();
        sd.setLogisticsTag(logisticsTag);
        shopDistributionService.updateShopDistributionByShopId(sd, shopId);
    }

    @Transactional(rollbackFor = Throwable.class)
    public void changeShopLocalDeliveryTag(String shopId, Integer localDeliveryTag, String userId) {
        Shop entity = new Shop();
        entity.setId(shopId);
//        entity.setLogisticsTag(localDeliveryTag);
        entity.setLocalDeliveryTag(localDeliveryTag);
        entity.setGmtModified(Instant.now());
        entity.setModifiedUserId(userId);
        shopDao.updateByPrimaryKeySelective(entity);
        checkLogistic(shopId);
        ShopDistribution sd = new ShopDistribution();
        sd.setLocalDeliveryTag(localDeliveryTag);
        shopDistributionService.updateShopDistributionByShopId(sd, shopId);
    }

    @Transactional(rollbackFor = Throwable.class)
    public void changeShopSelfMention(String shopId, Integer selfMentionTag, String userId) {
        Shop entity = new Shop();
        entity.setId(shopId);
        entity.setSelfMentionTag(selfMentionTag);
        entity.setGmtModified(Instant.now());
        entity.setModifiedUserId(userId);
        shopDao.updateByPrimaryKeySelective(entity);
        checkLogistic(shopId);
        ShopDistribution sd = new ShopDistribution();
        sd.setSelfMentionTag(selfMentionTag);
        shopDistributionService.updateShopDistributionByShopId(sd, shopId);
    }

    private void checkLogistic(String shopId) {
        Shop shop = shopDao.selectByPrimaryKey(shopId);
        ParamException.isTrue(shop != null && BaseEnum.StatusEnum.DISABLE.getCode().equals(shop.getLogisticsTag()) && BaseEnum.StatusEnum.DISABLE.getCode().equals(shop.getLocalDeliveryTag()) && BaseEnum.StatusEnum.DISABLE.getCode().equals(shop.getSelfMentionTag()), "物流方式至少开启一个");
    }

    public ShopOrderDataVo getData(String shopId) {
        ShopOrderDataVo shopOrderDataVo = orderApi.getShopData(shopId).getResult();
        QueryShopUserRecordBo bo = new QueryShopUserRecordBo();
        bo.setShopId(shopId);
        Integer integer = shopUserRecordDao.queryConsumeCount(bo);
        if (integer == null) {
            shopOrderDataVo.setConsumerUser(0);
        } else {
            shopOrderDataVo.setConsumerUser(integer);
        }
        bo.setStartTime(DateUtil.getTimesMorning());
        bo.setEndTime(Instant.now());
        Integer integer1 = shopUserRecordDao.queryConsumeCount(bo);
        if (integer1 == null) {
            shopOrderDataVo.setConsumerUser(0);
        } else {
            shopOrderDataVo.setTodayConsumerUser(integer1);
        }
        return shopOrderDataVo;
    }

    public Map<String, ShopSupplyVo> getByIds(List<String> ids) {
        List<ShopSupplyVo> shopVos = BeanConverUtils.convertBeanList(shopDao.selectByPrimaryKeys(ids), ShopSupplyVo.class);
        List<ShopDistribution> list = shopDistributionService.getByShopIds(ids);
        Map<String, ShopDistribution> distributionMap = list.stream().collect(Collectors.toMap(ShopDistribution::getShopId, Function.identity(), (k1, k2) -> k1));
        return shopVos.stream().map(shopSupplyVo -> {
            ShopDistribution shopDistribution = distributionMap.getOrDefault(shopSupplyVo.getId(), new ShopDistribution());
            shopSupplyVo.setAddress(shopDistribution.getTakeAddr());
            shopSupplyVo.setBusBegin(shopDistribution.getBusBegin());
            shopSupplyVo.setBusEnd(shopDistribution.getBusEnd());
            shopSupplyVo.setSelfMentionTag(shopDistribution.getSelfMentionTag());
            shopSupplyVo.setLocalDeliveryTag(shopDistribution.getLocalDeliveryTag());
            shopSupplyVo.setLogisticsTag(shopDistribution.getLogisticsTag());
            return shopSupplyVo;
        }).collect(Collectors.toMap(ShopSupplyVo::getId, Function.identity()));
    }

    public ShopVo getShopById(String id) {
        return BeanConverUtils.convertBean(shopDao.selectByPrimaryKey(id), ShopVo.class);
    }

    /**
     * 附近门店
     *
     * @param boPageBo
     * @return
     */
    public PageVo<ShopVo> getNearShop(PageBo<QueryNearShopBo> boPageBo) {
        List<ShopLoc> shopLocs = shopLocRepository.near(boPageBo.getParam(), boPageBo.getPage(), boPageBo.getPageSize());
        if (shopLocs.isEmpty()) {
            PageInfo<ShopVo> info = new PageInfo(new ArrayList(0));
            return new PageVo<>(info.getTotal(), boPageBo.getPage(), boPageBo.getPageSize(), info.getList());
        }
        List<String> shopIds = shopLocs.stream().map(ShopLoc::getShopId).collect(Collectors.toList());
        List<Shop> shops = shopDao.selectByPrimaryKeys(shopIds);
        Map<String, Shop> shopMap = shops.stream().collect(Collectors.toMap(Shop::getId, Function.identity()));
        List<ShopVo> shopVos = shopLocs.stream().filter(shopLoc -> shopMap.containsKey(shopLoc.getShopId())).map(shopLoc -> {
            Shop shop = shopMap.get(shopLoc.getShopId());
            ShopVo shopVo = BeanConverUtils.convertBean(shop, ShopVo.class);
            setShopStoreImg(shop.getStoreImg1(), shopVo);
            shopVo.setDistance(BigDecimal.valueOf(shopLoc.getDistance() * 1000).setScale(1, RoundingMode.HALF_UP).doubleValue());
            return shopVo;
        }).collect(Collectors.toList());
        setCategoryNameForList(shopVos);
        PageInfo<ShopVo> info = new PageInfo(shopVos);
        return new PageVo<>(info.getTotal(), boPageBo.getPage(), boPageBo.getPageSize(), info.getList());

    }

    private void setCategoryNameForList(List<ShopVo> shopVos) {
        Set<String> set = new HashSet<>();
        shopVos.forEach(
                shopVo -> set.addAll(Arrays.asList(Optional.ofNullable(shopVo.getCategory()).orElse("").split(",")))
        );
        List<ShopCategoryVo> shopCategorys = shopCategoryService.getByCodeList(new ArrayList<>(set));
        Map<String, String> categoryMap = shopCategorys.stream().collect(Collectors.toMap(ShopCategoryVo::getShopCategoryCode, ShopCategoryVo::getShopCategoryName, (k1, k2) -> k1));
        shopVos.forEach(shopVo -> {
            StringJoiner sj = new StringJoiner(",");
            Stream.of(Optional.ofNullable(shopVo.getCategory()).orElse("").split(",")).forEach(s -> sj.add(categoryMap.get(s)));
            shopVo.setShopCategoryName(sj.toString());
        });
    }

    public PageVo<ShopVo> getResentShop(PageBo<QueryResentShopBo> boPageBo, String userId) {
        if (boPageBo.getParam().getQueryDays() != null) {
            boPageBo.getParam().setBeginDay(DateUtil.getTimesMorning(-boPageBo.getParam().getQueryDays()));
        }
        boPageBo.getParam().setUserId(userId);
        PageHelper.startPage(boPageBo.getPage(), boPageBo.getPageSize(), MySqlUtil.orderBy(boPageBo.getSort(), boPageBo.isAsc()));
        List<Shop> shops = shopDao.getResentShop(boPageBo.getParam());
        if (shops == null || shops.size() == 0) {
            shops.add(BeanConverUtils.convertBean(getDefaultShop(), Shop.class));
        }
/*        //计算距离
        List<String> idlist = shops.stream().map(Shop::getId).collect(Collectors.toList());
        QueryNearShopBo bo=new QueryNearShopBo();
        bo.setIdList(idlist);
        bo.setLat(boPageBo.getParam().getLat());
        bo.setLng(boPageBo.getParam().getLng());
        bo.setLongDistance(100000.0);
        List<ShopDto> shopDtos = shopDao.queryNearShop(bo);*/
        List<ShopVo> shopVos = new ArrayList<>();
        for (Shop shop : shops) {
            ShopVo shopVo = BeanConverUtils.convertBean(shop, ShopVo.class);
            setShopStoreImg(shop.getStoreImg1(), shopVo);
            setShopCategoryName(shopVo);
            shopVos.add(shopVo);
        }
        PageInfo<ShopVo> info = new PageInfo(shopVos);
        return new PageVo<>(info.getTotal(), boPageBo.getPage(), boPageBo.getPageSize(), info.getList());
    }

    public PageVo<ShopVo> searchShopForWbm(PageBo<SearchShopBo> boPageBo, String userId) {
        PageHelper.startPage(boPageBo.getPage(), boPageBo.getPageSize(), MySqlUtil.orderBy(boPageBo.getSort(), boPageBo.isAsc()));
        List<Shop> shops = shopDao.searchShop(boPageBo.getParam());
        List<ShopVo> shopVos = new ArrayList<>();
        for (Shop shop : shops) {
            ShopVo shopVo = BeanConverUtils.convertBean(shop, ShopVo.class);
            setShopStoreImg(shop.getStoreImg1(), shopVo);
            setShopCategoryName(shopVo);
            if (StringUtil.isNotEmpty(userId)) {
                ShopMember shopMember = shopMemberDao.checkShop(shop.getId(), userId);
                if (shopMember != null) {
                    shopVo.setIsMember(1);
                } else {
                    shopVo.setIsMember(0);
                }
            }
            shopVos.add(shopVo);
        }

        PageInfo<ShopVo> info = new PageInfo(shopVos);
        return new PageVo<>(info.getTotal(), boPageBo.getPage(), boPageBo.getPageSize(), info.getList());
    }

    public List<ShopVo> getShopListByIds(Collection<String> shopIds) {
        return BeanConverUtils.convertBeanList(shopDao.selectByPrimaryKeys(shopIds), ShopVo.class);
    }

    public List<ShopVo> searchShop(SearchShopBo bo) {
        return BeanConverUtils.convertBeanList(shopDao.searchShop(bo), ShopVo.class);
    }

    public void createWxaCode() {
        List<Shop> list = shopDao.selectAll();
        if (!CollectionUtils.isEmpty(list)) {
            for (Shop shop : list) {
                if (StrUtil.isNotEmpty(shop.getLogo())) {
                    String logoUrl = shop.getLogo();
                    String logoStr = logoUrl.substring(logoUrl.lastIndexOf("/", logoUrl.lastIndexOf("/") - 1) + 1);
                    ((ShopService) AopContext.currentProxy()).customizeLogoWxaCode(shop.getId(), shop.getUserId(), logoStr);
                } else {
                    ((ShopService) AopContext.currentProxy()).createShopWxaCode(shop.getId(), shop.getUserId());
                }
            }
        }
    }

    public ShopVo getSimpleShopByUserId(String userId) {
        Shop shop = new Shop();
        shop.setUserId(userId);
        return BeanConverUtils.convertBean(shopDao.selectOne(shop), ShopVo.class);
    }

    public List<ShopVo> getSimpleShopByUserIds(List<String> userIds) {
        List<ShopVo> shopVos = BeanConverUtils.convertBeanList(shopDao.getShopByUserIds(userIds), ShopVo.class);
        setCategoryNameForList(shopVos);
        return shopVos;
    }

    public String getUserShopByUserId(String userId) {
        Shop shop = new Shop();
        shop.setUserId(userId);
        Shop shop1 = shopDao.selectOne(shop);
        if (shop1 == null) {
            return null;
        }
        return shop1.getId();
    }

    public String getShopWxaCode(String shopId) {
        Shop entity = shopDao.selectByPrimaryKey(shopId);
        ParamException.isNull(entity);
        saveShareCodeInfoToRedis(shopId);
        String logoStr = "";
        if (StrUtil.isNotEmpty(entity.getLogo())) {
            String logoUrl = entity.getLogo();
            int index = logoUrl.lastIndexOf("/", logoUrl.lastIndexOf("/") - 1) + 1;
            if (index > 0) {
                logoStr = logoUrl.substring(index);
            }
        }
        RestVo<String> stringRestVo = gateApi.getShopWxaCode(shopId, BaseEnum.WxAppId.WBM.getCode(), logoStr);
        return stringRestVo.getResult();
    }

    public ShopVo judgeUserHasShop(String userId, String shopId) {
        ShopVo shopVo = getSimpleShopByUserId(userId);
        if (null != shopVo && shopId.equals(shopVo.getId())) {
            return shopVo;
        }
        ShopStaff ss = new ShopStaff();
        ss.setShopId(shopId);
        ss.setUserId(userId);
        ShopStaff exist = shopStaffDao.selectOne(ss);
        if (null != exist) {
            return getShopById(exist.getShopId());
        }
        return null;
    }

    public void syncShopLoc() {
        List<Shop> shops = shopDao.selectAll();
        List<ShopLoc> shopLocs = shops.stream().filter(shop -> shop.getLat() != null && shop.getLng() != null).map(shop -> {
            ShopLoc shopLoc = BeanConverUtils.convertBean(shop, ShopLoc.class);
            shopLoc.setShopId(shop.getId());
            shopLoc.setLoc(new Location(shop.getLng(), shop.getLat()));
            return shopLoc;
        }).collect(Collectors.toList());
        shopLocRepository.saveAll(shopLocs);
    }

    public PageVo<ShopVo> agentShopPage(PageBo pageBo, String itemId) {
        List<String> shopIds = goodsApi.agentShopIds(itemId).getResult();
        if (CollectionUtils.isEmpty(shopIds)) {
            return new PageVo<>();
        }
        PageHelper.startPage(pageBo.getPage(), pageBo.getPageSize(), MySqlUtil.orderBy(pageBo.getSort(), pageBo.isAsc()));
        PageInfo<Shop> info = new PageInfo<>(shopDao.selectByPrimaryKeys(shopIds));
        List<ShopVo> list = BeanConverUtils.convertBeanList(info.getList(), ShopVo.class);
        return new PageVo<>(info.getTotal(), pageBo.getPage(), pageBo.getPageSize(), list);
    }
}
